home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-06-21 | 19.4 KB | 791 lines | [TEXT/CWIE] |
- // ===========================================================================
- // LTextEdit.cp ©1993-1996 Metrowerks Inc. All rights reserved.
- // ===========================================================================
- //
- // ### Still under moderate construction
- // * Doesn't autoscroll while typing or selecting
- // * Doesn't adjust to display whole lines
- // * Doesn't undo
-
- #ifdef PowerPlant_PCH
- #include PowerPlant_PCH
- #endif
-
- #include "LStyledTextEdit.h"
-
- #include <LStream.h>
- #include <UTextTraits.h>
- #include <UDrawingState.h>
- #include <UMemoryMgr.h>
- #include <UKeyFilters.h>
- #include <PP_KeyCodes.h>
- #include <PP_Messages.h>
-
- #ifndef __SCRAP__
- #include <Scrap.h>
- #endif
-
- #ifndef __SCRIPT__
- #include <Script.h>
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
-
- // ---------------------------------------------------------------------------
- // • CreateStyledTextEditStream
- // ---------------------------------------------------------------------------
- // Create a new StyledTextEdit object from the data in a Stream
-
- LStyledTextEdit*
- LStyledTextEdit::CreateStyledTextEditStream(
- LStream *inStream)
- {
- return (new LStyledTextEdit(inStream));
- }
-
-
- // ---------------------------------------------------------------------------
- // • LStyledTextEdit
- // ---------------------------------------------------------------------------
- // Default Contructor
-
- LStyledTextEdit::LStyledTextEdit()
- {
- mTextAttributes = 0;
- InitStyledTextEdit(0); // Initialize member variables
- AlignTextEditRects();
- }
-
-
- // ---------------------------------------------------------------------------
- // • LStyledTextEdit
- // ---------------------------------------------------------------------------
- // Construct from input parameters
-
- LStyledTextEdit::LStyledTextEdit(
- const SPaneInfo &inPaneInfo,
- const SViewInfo &inViewInfo,
- Uint16 inTextAttributes,
- ResIDT inTextTraitsID)
- : LView(inPaneInfo, inViewInfo)
- {
- mTextAttributes = inTextAttributes;
- InitStyledTextEdit(inTextTraitsID);
- AlignTextEditRects();
- }
-
-
- // ---------------------------------------------------------------------------
- // • LStyledTextEdit(LStream*)
- // ---------------------------------------------------------------------------
- // Contruct an StyledTextEdit from the data in a Stream
-
- LStyledTextEdit::LStyledTextEdit(
- LStream *inStream)
- : LView(inStream)
- {
- inStream->ReadData(&mTextAttributes, sizeof(Uint16));
-
- ResIDT textTraitsID;
- inStream->ReadData(&textTraitsID, sizeof(ResIDT));
-
- ResIDT initialTextID;
- inStream->ReadData(&initialTextID, sizeof(ResIDT));
-
- InitStyledTextEdit(textTraitsID);
- AlignTextEditRects();
-
- Handle initialTextH = ::GetResource('TEXT', initialTextID);
- if (initialTextH != nil) {
- SetTextHandle(initialTextH);
- ::ReleaseResource(initialTextH);
- ::TESetSelect(0, 0, mTextEditH);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • InitStyledTextEdit
- // ---------------------------------------------------------------------------
- // Initialize member variables of a StyledTextEdit to default values
-
- void
- LStyledTextEdit::InitStyledTextEdit(
- ResIDT inTextTraitsID)
- {
- Rect viewRect = {0, 0, 0, 0};
- mTextEditH = ::TEStyleNew(&viewRect, &viewRect);
-
- SetTextTraitsID(inTextTraitsID);
-
- // If word wrap is on, then the Image width is always the
- // same as the Frame width, which forces text to wrap to
- // the Frame.
-
- // If the Image width is zero (or negative), the user
- // probably forgot to set it. To accommodate this error,
- // we set the Image width to the Frame width. However, the
- // Image will not change if the Frame resizes.
-
- if ((mTextAttributes & textAttr_WordWrap) ||
- (mImageSize.width <= 0)) {
- mImageSize.width = mFrameSize.width;
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • ~LStyledTextEdit
- // ---------------------------------------------------------------------------
- // Destructor
-
- LStyledTextEdit::~LStyledTextEdit()
- {
- if (mTextEditH != nil) {
- ::TEDispose(mTextEditH);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • SetTextHandle
- // ---------------------------------------------------------------------------
- // Set the text in the LTextEdit to the contents of the specified Handle
- //
- // The LTextEdit copies the data in the Handle, so the caller retains
- // ownership of the Handle (and should dispose of it as needed)
-
- void
- LStyledTextEdit::SetTextHandle(
- Handle inTextH, TEStyleHandle inStylH)
- {
- StHandleLocker lock(inTextH);
-
- if( inStylH )
- {
- ::TEStyleInsert(*inTextH, ::GetHandleSize(inTextH), (StScrpHandle)inStylH, mTextEditH );
- ::TECalText(mTextEditH);
- AdjustImageToText();
- Refresh();
- }
- else
- SetTextPtr( *inTextH, ::GetHandleSize(inTextH) );
-
- }
-
-
-
- void
- LStyledTextEdit::SetTextPtr(
- Ptr inTextP,
- Int32 inTextLen)
- {
- ::TESetText(inTextP, inTextLen, mTextEditH);
- ::TECalText(mTextEditH);
- AdjustImageToText();
- Refresh();
- }
-
-
- // ---------------------------------------------------------------------------
- // • GetMacTEH
- // ---------------------------------------------------------------------------
- // Return a Handle to the text in the LStyledTextEdit
- //
- // The Handle is the actual Handle used by the Toolbox StyledTextEdit record.
- // Treat this Handle as read-only
-
- Handle
- LStyledTextEdit::GetTextHandle()
- {
- return (Handle) ::TEGetText(mTextEditH);
- }
-
- StScrpHandle
- LStyledTextEdit::GetStyleScrapHandle()
- {
- StScrpHandle theStyleScrapHandle;
-
- short oldStart,
- oldEnd;
-
- oldStart = (**mTextEditH).selStart;
- oldEnd = (**mTextEditH).selEnd;
-
- (** mTextEditH).selStart = 0;
- (** mTextEditH).selEnd = 32767;
- theStyleScrapHandle = ::TEGetStyleScrapHandle(mTextEditH);
- (**mTextEditH).selStart = oldStart;
- (**mTextEditH).selEnd = oldEnd;
-
- return theStyleScrapHandle;
- }
-
-
- // ---------------------------------------------------------------------------
- // • GetMacTEH
- // ---------------------------------------------------------------------------
- // Return a Handle to the Mac StyledTextEdit Record associated with an StyledTextEdit
- //
- // Caller may change record fields, and is responsible for redrawing the
- // StyledTextEdit as necessary to reflect any changes. However, caller must
- // not dispose of the TEHandle.
-
- TEHandle
- LStyledTextEdit::GetMacTEH()
- {
- return mTextEditH;
- }
-
-
- // ---------------------------------------------------------------------------
- // • SetTextTraitsID
- // ---------------------------------------------------------------------------
- // Specify the resource ID of the TextTraits for an StyledTextEdit
- //
- // This function updates the line height to fit the text characteristics.
-
- void
- LStyledTextEdit::SetTextTraitsID(
- ResIDT inTextTraitsID)
- {
- mTextTraitsID = inTextTraitsID;
- //UTextTraits::SetTETextTraits(mTextTraitsID, mTextEditH);
-
- SPoint32 scrollUnit;
- scrollUnit.h = 4;
- scrollUnit.v = 12; //(**mTextEditH).lineHeight;
- SetScrollUnit(scrollUnit);
- }
-
-
- Boolean
- LStyledTextEdit::HasAttribute(
- Uint16 inAttribute)
- {
- return ((mTextAttributes & inAttribute) != 0);
- }
-
-
- Boolean
- LStyledTextEdit::FocusDraw()
- {
- Boolean focused = LView::FocusDraw();
- if (focused) {
- StColorPenState::Normalize();
- //UTextTraits::SetPortTextTraits(mTextTraitsID);
- }
-
- return focused;
- }
-
-
- // ---------------------------------------------------------------------------
- // • DrawSelf
- // ---------------------------------------------------------------------------
- // Draw a StyledTextEdit
-
- void
- LStyledTextEdit::DrawSelf()
- {
- Rect frame;
- CalcLocalFrameRect(frame);
-
- // A Mac TERec stores a pointer to its owner port We have to
- // change it to the current port in case we are drawing into
- // a port that is not the owner port. This happens when we are
- // printing or drawing into an offscreen port.
-
- GrafPtr savePort = (**mTextEditH).inPort;
- (**mTextEditH).inPort = UQDGlobals::GetCurrentPort();
-
- ::TEUpdate(&frame, mTextEditH);
-
- (**mTextEditH).inPort = savePort;
- }
-
-
- // ---------------------------------------------------------------------------
- // • HideSelf
- // ---------------------------------------------------------------------------
- // Hide an LStyledTextEdit. An invisible LStyledTextEdit can't be OnDuty.
-
- void
- LStyledTextEdit::HideSelf()
- {
- if (IsOnDuty()) { // Shouldn't be on duty when invisible
- SwitchTarget(GetSuperCommander());
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • ClickSelf
- // ---------------------------------------------------------------------------
- // Respond to Click inside an StyledTextEdit
-
- void
- LStyledTextEdit::ClickSelf(
- const SMouseDownEvent &inMouseDown)
- {
- if (!HasAttribute(textAttr_Selectable)) {
- return;
- }
-
- if (!IsTarget()) { // If not the Target, clicking in an
- // TextEdit makes it the Target.
- // Since TEClick will set a new selection
- // range, clear the current selection
- // range to avoid an ugly flash.
- ::TESetSelect(0, 0, mTextEditH);
- SwitchTarget(this);
- }
-
- if (IsTarget()) {
- FocusDraw();
- ::TEClick(inMouseDown.whereLocal,
- ((inMouseDown.macEvent.modifiers & shiftKey) != 0),
- mTextEditH);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • AdjustCursorSelf
- // ---------------------------------------------------------------------------
- // StyledTextEdit uses the standard I-Beam cursor
-
- void
- LStyledTextEdit::AdjustCursorSelf(
- Point /* inPortPt */,
- const EventRecord& /* inMacEvent */)
- {
- CursHandle theCursH = ::GetCursor(iBeamCursor);
- if (theCursH != nil) {
- ::SetCursor(*theCursH);
- }
- }
-
-
- Boolean
- LStyledTextEdit::ObeyCommand(
- CommandT inCommand,
- void* ioParam)
- {
- Boolean cmdHandled = true;
-
- switch (inCommand) {
-
- case cmd_Cut:
- ::ZeroScrap();
- ::TECut(mTextEditH);
- ::TEToScrap();
- AdjustImageToText();
- UserChangedText();
- break;
-
- case cmd_Copy:
- ::ZeroScrap();
- ::TECopy(mTextEditH);
- ::TEToScrap();
- break;
-
- case cmd_Paste:
- ::TEFromScrap();
- ::TEStylePaste(mTextEditH);
- AdjustImageToText();
- UserChangedText();
- break;
-
- case cmd_Clear: {
- ::TEDelete(mTextEditH);
- AdjustImageToText();
- UserChangedText();
- break;
- }
-
- case msg_TabSelect:
- if (!IsEnabled()) {
- cmdHandled = false;
- break;
- } // else FALL THRU to SelectAll()
-
- case cmd_SelectAll:
- SelectAll();
- break;
-
- default:
- cmdHandled = LCommander::ObeyCommand(inCommand, ioParam);
- break;
- }
-
- return cmdHandled;
- }
-
-
- void
- LStyledTextEdit::FindCommandStatus(
- CommandT inCommand,
- Boolean &outEnabled,
- Boolean &outUsesMark,
- Char16 &outMark,
- Str255 outName)
- {
- outUsesMark = false;
-
- switch (inCommand) {
-
- case cmd_Copy: // Copy enabled if something is selected
- outEnabled = ((**mTextEditH).selStart != (**mTextEditH).selEnd);
- break;
-
- case cmd_Cut: // Cut and Clear enabled if editabled
- case cmd_Clear: // and something is selected
- outEnabled = HasAttribute(textAttr_Editable) &&
- ((**mTextEditH).selStart != (**mTextEditH).selEnd);
- break;
-
- case cmd_Paste: { // Pasted enabled if editable and
- Int32 offset; // TEXT is on the Scrap
- outEnabled = HasAttribute(textAttr_Editable) &&
- (::GetScrap(nil, 'TEXT', &offset) > 0);
- break;
- }
-
- case cmd_SelectAll: // Check if any characters are present
- outEnabled = HasAttribute(textAttr_Selectable) &&
- ((**mTextEditH).teLength > 0);
-
- break;
-
- default:
- LCommander::FindCommandStatus(inCommand, outEnabled,
- outUsesMark, outMark, outName);
- break;
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • HandleKeyPress
- // ---------------------------------------------------------------------------
- // Handle key stroke directed at an StyledTextEdit
- //
- // Return true if the StyledTextEdit handles the keystroke
-
- Boolean
- LStyledTextEdit::HandleKeyPress(
- const EventRecord& inKeyEvent)
- {
- Boolean keyHandled = true;
- EKeyStatus theKeyStatus = keyStatus_Input;
- Int16 theKey = inKeyEvent.message & charCodeMask;
-
- if (inKeyEvent.modifiers & cmdKey) { // Always pass up when the command
- theKeyStatus = keyStatus_PassUp; // key is down
- } else {
-
- theKeyStatus = UKeyFilters::PrintingCharField(inKeyEvent);
- }
-
- if ((theKeyStatus == keyStatus_PassUp) && (theKey == char_Return)) {
- theKeyStatus = keyStatus_Input; // Special case for Return key
- }
-
- if (!HasAttribute(textAttr_Editable)) { // Disallow editing
- theKeyStatus = keyStatus_PassUp;
- }
-
- short lineCount = (**mTextEditH).nLines;
-
- switch (theKeyStatus) {
-
- case keyStatus_Input:
- case keyStatus_TEDelete:
- FocusDraw();
- ::TEKey(theKey, mTextEditH);
- UserChangedText();
- break;
-
- case keyStatus_TECursor:
- FocusDraw();
- ::TEKey(theKey, mTextEditH);
- break;
-
- case keyStatus_ExtraEdit:
- if (theKey == char_FwdDelete) {
- FocusDraw();
- if (((**mTextEditH).selStart == (**mTextEditH).selEnd) &&
- ((**mTextEditH).selStart < (**mTextEditH).teLength) ) {
- ::TESetSelect((**mTextEditH).selStart + 1,
- (**mTextEditH).selStart + 1,
- mTextEditH);
- ::TEKey(char_Backspace, mTextEditH);
- } else {
- ::TEDelete(mTextEditH);
- }
-
- } else {
- keyHandled = LCommander::HandleKeyPress(inKeyEvent);
- }
- break;
-
- case keyStatus_Reject:
- // +++ Do something
- SysBeep(1);
- break;
-
- case keyStatus_PassUp:
- keyHandled = LCommander::HandleKeyPress(inKeyEvent);
- break;
- }
-
- if (lineCount != (**mTextEditH).nLines) {
- AdjustImageToText();
- }
-
- return keyHandled;
- }
-
-
- // ---------------------------------------------------------------------------
- // • SelectAll
- // ---------------------------------------------------------------------------
- // Select entire contents of an StyledTextEdit
-
- void
- LStyledTextEdit::SelectAll()
- {
- if (HasAttribute(textAttr_Selectable)) {
- FocusDraw();
- ::TESetSelect(0, 32767, mTextEditH);
- }
- }
-
- // ---------------------------------------------------------------------------
- // • SelectNone
- // ---------------------------------------------------------------------------
- // Select entire contents of an StyledTextEdit
-
- void
- LStyledTextEdit::SelectNone()
- {
- if (HasAttribute(textAttr_Selectable)) {
- FocusDraw();
- ::TESetSelect(0, 0, mTextEditH);
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • AlignTextEditRects
- // ---------------------------------------------------------------------------
- // Align the view and destination rectangles of the Toolbox TextEdit
- // record with the Frame of a TextEdit
-
- void
- LStyledTextEdit::AlignTextEditRects()
- {
- Rect textFrame;
- if (CalcLocalFrameRect(textFrame)) {
- // TextEdit view rect same as Frame
- // in local coords
- (**mTextEditH).viewRect = textFrame;
-
- // TextEdit dest rect same as Image
- // in local coords
- SPoint32 imagePt = {0, 0};
- ImageToLocalPoint(imagePt, topLeft((**mTextEditH).destRect));
-
- // Bottom of dest rect is ignored
- imagePt.h = mImageSize.width;
- ImageToLocalPoint(imagePt, botRight((**mTextEditH).destRect));
-
- ::TECalText(mTextEditH); // Let TextEdit adjust line breaks
- }
- }
-
-
- void
- LStyledTextEdit::AdjustImageToText()
- {
- ResizeImageTo(mImageSize.width,
- ::TEGetHeight((**mTextEditH).nLines, 1, mTextEditH),
- false);
- }
-
-
- // ---------------------------------------------------------------------------
- // • ResizeFrameBy
- // ---------------------------------------------------------------------------
- // Change the Frame size by the specified amounts
- //
- // inWidthDelta and inHeightDelta specify, in pixels, how much larger
- // to make the Frame. Positive deltas increase the size, negative deltas
- // reduce the size.
-
- void
- LStyledTextEdit::ResizeFrameBy(
- Int16 inWidthDelta,
- Int16 inHeightDelta,
- Boolean inRefresh)
- {
- // Resize Pane
- LView::ResizeFrameBy(inWidthDelta, inHeightDelta, inRefresh);
-
- if (mTextAttributes & textAttr_WordWrap) {
- ResizeImageTo(mFrameSize.width, mImageSize.height, false);
- }
-
- AlignTextEditRects();
- AdjustImageToText();
- }
-
-
- // ---------------------------------------------------------------------------
- // • MoveBy
- // ---------------------------------------------------------------------------
- // Move the location of the Frame by the specified amounts
- //
- // inHorizDelta and inVertDelta specify, in pixels, how far to move the
- // Frame (within its surrounding Image). Positive horiz deltas move to
- // the right, negative to the left. Positive vert deltas move down,
- // negative up.
-
- void
- LStyledTextEdit::MoveBy(
- Int32 inHorizDelta,
- Int32 inVertDelta,
- Boolean inRefresh)
- {
- LView::MoveBy(inHorizDelta, inVertDelta, inRefresh);
- AlignTextEditRects();
- }
-
-
- // ---------------------------------------------------------------------------
- // • ScrollImageBy
- // ---------------------------------------------------------------------------
- // Scroll the Text
-
- void
- LStyledTextEdit::ScrollImageBy(
- Int32 inLeftDelta, // Pixels to scroll horizontally
- Int32 inTopDelta, // Pixels to scroll vertically
- Boolean inRefresh)
- {
- OffsetRect(&(**mTextEditH).viewRect, inLeftDelta, inTopDelta);
-
- LView::ScrollImageBy(inLeftDelta, inTopDelta, inRefresh);
- }
-
-
- // ---------------------------------------------------------------------------
- // • BeTarget
- // ---------------------------------------------------------------------------
- // StyledTextEdit is becoming the Target
-
- void
- LStyledTextEdit::BeTarget()
- {
- if (FocusDraw()) { // Show active selection
- ::TEActivate(mTextEditH); // ??? What if we can't Focus ???
- }
- StartIdling(); // Idle time used to flash the cursor
- }
-
-
- // ---------------------------------------------------------------------------
- // • DontBeTarget
- // ---------------------------------------------------------------------------
- // StyledTextEdit is no longer the Target
- //
- // Remove StyledTextEdit from IdleQueue
-
- void
- LStyledTextEdit::DontBeTarget()
- {
- if (FocusDraw()) { // Show inactive selection
- ::TEDeactivate(mTextEditH);
- }
- StopIdling(); // Stop flashing the cursor
- }
-
-
- // ---------------------------------------------------------------------------
- // • SpendTime
- // ---------------------------------------------------------------------------
- // Idle time: Flash the insertion cursor
-
- void
- LStyledTextEdit::SpendTime(
- const EventRecord& /* inMacEvent */)
- {
- if (FocusDraw() & IsVisible() & HasAttribute(textAttr_Selectable)) {
- ::TEIdle(mTextEditH);
- }
- }
-
- // ---------------------------------------------------------------------------
- // • UserChangedText
- // ---------------------------------------------------------------------------
- // Text of TextEdit has changed as a result of user action
- //
- // Override to validate field and/or dynamically update as the user
- // types. This function is not called by SetDescriptor, which is typically
- // used to programatically change the text.
-
- void
- LStyledTextEdit::UserChangedText()
- {
- }
-
-
- SStyledTextEditUndoH
- LStyledTextEdit::SaveStateForUndo()
- {
- SStyledTextEditUndoH theUndoH = (SStyledTextEditUndoH)
- ::NewHandle(sizeof(STextEditUndo));
- ThrowIfMemFail_(theUndoH);
-
- Handle currTextH = (**mTextEditH).hText;
- ::HandToHand(&currTextH);
- (**theUndoH).textH = currTextH;
- (**theUndoH).selStart = (**mTextEditH).selStart;
- (**theUndoH).selEnd = (**mTextEditH).selEnd;
-
- return theUndoH;
- }
-
-
- void
- LStyledTextEdit::SavePlace(
- LStream *outPlace)
- {
- LView::SavePlace(outPlace);
-
- Rect viewRect = (**mTextEditH).viewRect;
- outPlace->WriteData(&viewRect, sizeof(Rect));
- Rect destRect = (**mTextEditH).destRect;
- outPlace->WriteData(&destRect, sizeof(Rect));
- }
-
-
- void
- LStyledTextEdit::RestorePlace(
- LStream *inPlace)
- {
- LView::RestorePlace(inPlace);
-
- Rect viewRect;
- inPlace->ReadData(&viewRect, sizeof(Rect));
- (**mTextEditH).viewRect = viewRect;
-
- Rect destRect;
- inPlace->ReadData(&destRect, sizeof(Rect));
- (**mTextEditH).destRect = destRect;
- }
-